import { cloneDeep } from 'lodash-es'
import type { RequestConfig } from './request'

interface UseAxiosConfig<T> extends RequestConfig {
	method?: 'get' | 'post'
	IinitialData?: any
	immediate?: boolean
	formater?: (data: T) => T
	onSuccess?: (data: T) => void
	onError?: (error: Record<string, any>) => void
	onBefore?: () => Promise<any> | void
	onFinally?: () => void
}

function useAxios<T>({
	url,
	method = 'get',
	params = {},
	config = {},
	immediate = false,
	IinitialData = {},
	formater,
	onSuccess,
	onError,
	onFinally,
	onBefore
}: UseAxiosConfig<T>) {
	const loading = ref(false)
	const error = ref<Record<string, any> | null>(null)
	const data = ref(IinitialData) as Ref<T>
	const METHOD_ENUM = { get, post }
	const requestMethod = METHOD_ENUM[method]

	async function runAsync(extraParams?: Record<string, any>, extraUrl?: string) {
		let onBeforeParams
		if (onBefore) {
			onBeforeParams = await onBefore()
		}
		loading.value = true
		return requestMethod<T>({
			config,
			url: extraUrl || url,
			params: extraParams || onBeforeParams || params
		})
			.then(response => {
				response = formater ? formater(cloneDeep(response)) : response
				data.value = response
				loading.value = false
				onSuccess && onSuccess(response)
				return response
			})
			.catch(err => {
				error.value = err
				onError && onError(err)
				err && (loading.value = false)
				return Promise.reject(err)
			})
			.finally(() => onFinally && onFinally())
	}

	immediate && runAsync()

	return {
		error,
		data,
		loading,
		runAsync
	}
}

export { useAxios }
